﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RpcGenerator
{
    class ProxyGenerator
    {
        public static void Generate(Type type, IMessageSerializer serializer, List<MessageDescription> allDescriptions)
        {
            MessageDescriptionGenerator mdgenerator = new MessageDescriptionGenerator();
            List<MessageDescription> requestDescriptions = allDescriptions.Where(description => description.IsRequest == true).ToList();

            string proxyName = type.Name;
            if (proxyName[0] == 'I')
                proxyName = proxyName.Remove(0, 1);
            serializer.NewLine(string.Format("public class {0}Proxy : RpcProxy", proxyName));
            serializer.BeginBlock();
            serializer.NewLine(string.Format("public {0}Proxy(RpcDomain domain,int sessionid,RpcBroadCaster caster,RpcSessionService session)", proxyName));
            serializer.NewLine(string.Format("    : base(domain, sessionid,caster,session)", type.Name));
                serializer.BeginBlock();
            serializer.EndBlock();

            requestDescriptions.ForEach(description =>
            {
                serializer.NewLine();
                GenerateMethod(description, serializer);
                if (description.SupportBroadcast)
                {
                    serializer.NewLine();
                    GenerateBroadcastMethod(description, serializer);
                }
            });

            GenerateInvokeInfo(type, serializer);

            //List<MessageDescription> responseDescriptions = allDescriptions.Where(description => description.IsRequest == false).ToList();
            //responseDescriptions.ForEach(description => 
            //{
            //    serializer.NewLine();
            //    GenerateAsynMethod(description, serializer);
            //});
            serializer.EndBlock();
        }

        private static void GenerateInvokeInfo(Type type, IMessageSerializer serializer)
        {
            serializer.NewLine();
            serializer.NewLine("private static RpcInvoker GetRpcInvoker()");
            serializer.BeginBlock();
            {
                serializer.NewLine(string.Format("return {0}_Invoker.Instance;",type.Name));
            }
            serializer.EndBlock();

            serializer.NewLine("private static Type GetServiceType()");
            serializer.BeginBlock();
            {
                serializer.NewLine(string.Format("return typeof({0});",type.Name));
            }
            serializer.EndBlock();
        }

        private static void GenerateAsynMethod(MessageDescription description, IMessageSerializer serializer)
        {
            serializer.NewLine(string.Format("public static void On{0}(RpcProxy proxy,", description.Method.Method.Name));            
            if (description.Fields.Count > 0)
            {
                MessageFieldDescription lastField = description.Fields[description.Fields.Count - 1];
                description.Fields.ForEach(fieldDescription =>
                {
                    if (lastField != fieldDescription)
                    {
                        serializer.Apppend(string.Format("{0} {1},", fieldDescription.IsGenericType() ? fieldDescription.GenericTypeName : fieldDescription.Type.Name, fieldDescription.Name));
                    }
                    else
                    {
                        serializer.Apppend(string.Format("{0} {1}", fieldDescription.IsGenericType() ? fieldDescription.GenericTypeName : fieldDescription.Type.Name, fieldDescription.Name));
                    }
                });
            }
            serializer.Apppend(")");
            serializer.BeginBlock();
                serializer.NewLine(string.Format("{0} response = new {0}();", description.Name));
                description.Fields.ForEach(fieldDescription =>
                {
                    serializer.NewLine(string.Format("response.{0} = {0};", fieldDescription.Name));
                });
                serializer.NewLine(string.Format("proxy.Return(response,{0});", description.NeedEncrypt ? "true" : "false"));
            serializer.EndBlock();
        }

        private static void GenerateMethod(MessageDescription description, IMessageSerializer serializer)
        {
            serializer.NewLine(string.Format("public void {0}(", description.Method.Method.Name));
            if (description.Fields.Count > 0)
            {
                MessageFieldDescription lastField = description.Fields[description.Fields.Count - 1];
                description.Fields.ForEach(fieldDescription =>
                {
                    if (lastField != fieldDescription)
                    {
                        serializer.Apppend(string.Format("{0} {1},", fieldDescription.IsGenericType() ? fieldDescription.GenericTypeName : fieldDescription.Type.Name, fieldDescription.Name));
                    }
                    else
                    {
                        serializer.Apppend(string.Format("{0} {1}", fieldDescription.IsGenericType() ? fieldDescription.GenericTypeName : fieldDescription.Type.Name, fieldDescription.Name));
                    }
                });
            }
            if (description.Response != null)
            {
                if (description.Fields.Count > 0)
                    serializer.Apppend(",");
                string callbackTypeName = description.Response.Fields[0].IsGenericType()?description.Response.Fields[0].GenericTypeName:description.Response.Fields[0].Type.Name;
                serializer.Apppend(string.Format("Action<{0}> callback", callbackTypeName));                
            }
            serializer.Apppend(")");
            serializer.BeginBlock();
                serializer.NewLine(string.Format("{0} request = new {0}();", description.Name));
                description.Fields.ForEach(fieldDescription =>
                {
                    serializer.NewLine(string.Format("request.{0} = {0};", fieldDescription.Name));                
                });
                serializer.NewLine(string.Format("Invoke(request,{0},{1});", description.NeedEncrypt ? "true" : "false",
                                                                             description.Response != null?"callback":"null"));
            serializer.EndBlock();
        }

        private static void GenerateBroadcastMethod(MessageDescription description, IMessageSerializer serializer)
        {
            serializer.NewLine(string.Format("public static void Broadcast_{0}(", description.Method.Method.Name));
            serializer.Apppend("List<RpcProxy> proxies,");
            if (description.Fields.Count > 0)
            {
                MessageFieldDescription lastField = description.Fields[description.Fields.Count - 1];
                description.Fields.ForEach(fieldDescription =>
                {
                    if (lastField != fieldDescription)
                    {
                        serializer.Apppend(string.Format("{0} {1},", fieldDescription.IsGenericType() ? fieldDescription.GenericTypeName : fieldDescription.Type.Name, fieldDescription.Name));
                    }
                    else
                    {
                        serializer.Apppend(string.Format("{0} {1}", fieldDescription.IsGenericType() ? fieldDescription.GenericTypeName : fieldDescription.Type.Name, fieldDescription.Name));
                    }
                });
            }
            serializer.Apppend(")");
            serializer.BeginBlock();
                serializer.NewLine(string.Format("{0} request = new {0}();", description.Name));
                description.Fields.ForEach(fieldDescription =>
                {
                    serializer.NewLine(string.Format("request.{0} = {0};", fieldDescription.Name));
                });

                serializer.NewLine();
                serializer.NewLine("RpcBroadCaster caster = null;");
                serializer.NewLine("foreach(RpcProxy proxy in proxies)");
                serializer.BeginBlock();
                    serializer.NewLine("caster = proxy.PrepareBroadcast();");
                serializer.EndBlock();

                serializer.NewLine("if(null!=caster)");
                serializer.BeginBlock();
                    serializer.NewLine("caster.BroadCast(request);");
                serializer.EndBlock();

            serializer.EndBlock();
        }
    }
}
